package mutation;

import java.util.*;
import java.io.FileReader;
import java.io.BufferedReader;
import javax.vecmath.Vector3f;

import main.*;
import math.MatrixManipulation;


/**
 *  An operator  that impose conformational changes (mutations in the GA jargon) on proteins.
 *  To this end it uses libraries of  predefined, self avoiding local mutations. Each library includes mutations of the same length.
 */
public class MutationManager {
    private Dimensions dimensions;

    /** The set of  mutation libraries*/
    public MutationLibrary[] mutationLibraries;
    private MutationLibrary mutationLibrary;

    /** The mutation list. unsorted. just loaded from the file*/
    private List<Vector<Mutation>> mutationList;

    private MatrixManipulation matrixMan;

    private float pm;
    private Random random;
        
    /** The following collections are used by mutate(), and are saved as members to improve performance.*/
	private ArrayList<MutationLibraryEntry> candidates = new ArrayList<MutationLibraryEntry>();	
	private ArrayList<Vector3f> proteinPositions = new ArrayList<Vector3f>();
	
	/** times setconfirmation() failed. used for performance measuring*/
	public int numOfFailers = 0;    
	
	/** times setconfirmation() called. used for performance measuring*/
	public int numOfIterations = 0;
	
	/** temp Vectors used by activateMutationOnProtein(). Declared as members to avoid "new".*/
	private Vector3f v1 = new Vector3f();
	private Vector3f v2 = new Vector3f();
	private Vector3f v3 = new Vector3f();

    public MutationManager(Configuration config) {
        matrixMan = new MatrixManipulation(config.dimensions);
        this.random = config.random;
        dimensions = config.dimensions;
        int numberOfDirections = 3;
        if (config.dimensions == Dimensions.THREE)
            numberOfDirections = 5;

        loadData(config.mutationsFileName,numberOfDirections);
        buildDictionaries();
    }


    /**
     * Loading Mutations data from file
     *
     * @param fileName the file name
     * @param numberOfDirections the number of directions
     */
    private void loadData(String fileName, int numberOfDirections) {
        mutationList = readFromFile(fileName);
    }

    public LinkedList<Vector<Mutation>> readFromFile(String filename) {
		try {
			LinkedList<Vector<Mutation>> list = new LinkedList<Vector<Mutation>>();
			Vector<Mutation> currentVector = null;

			FileReader input = new FileReader(filename);
			BufferedReader bufRead = new BufferedReader(input);

			String line = bufRead.readLine();
			StringTokenizer sT;
			Mutation mutation;
			String chainStr,adjenciesStr,pairStr,firstVectorStr,lastVectorStr;
			Pair<Integer,Integer> pair;
			Integer pairNum1,pairNum2;
			while (line != null)  {
				if (line.charAt(0) != '#' && line.charAt(0) != '!' && line.trim().length() != 0) {//Skip Comments\ headers \ empty lines
					sT = new StringTokenizer(line,"\t");

					chainStr = sT.nextToken();
					chainStr = chainStr.substring(1, chainStr.length()-1);
					firstVectorStr = sT.nextToken();
					firstVectorStr = firstVectorStr.substring(1, firstVectorStr.length()-1);
					lastVectorStr = sT.nextToken();
					lastVectorStr = lastVectorStr.substring(1, lastVectorStr.length()-1);

					adjenciesStr = sT.nextToken();
					adjenciesStr = adjenciesStr.substring(1, adjenciesStr.length()-1);

					mutation = new Mutation(stringToVector(firstVectorStr),stringToVector(lastVectorStr),chainStr,0);

					if (adjenciesStr.length() != 0) {
						sT = new StringTokenizer(adjenciesStr,":");
						while (sT.hasMoreTokens()) {
							pairStr = sT.nextToken();
							pairNum1 = new Integer(pairStr.substring(pairStr.indexOf('<')+1, pairStr.indexOf(',')));
							pairNum2 = new Integer(pairStr.substring(pairStr.indexOf(',')+1).replace(">", ""));
							pair = new Pair<Integer, Integer>(pairNum1,pairNum2);
							mutation.getAdjacencyList().add(pair);
						}
					}
					currentVector.add(mutation);
				}
				else if (line.charAt(0) == '!') //if header
				{
					currentVector = new Vector<Mutation>();
					list.addLast(currentVector);
				}
				line = bufRead.readLine();
			}
			bufRead.close();
			return list;
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		return null;
	}

    /**
	 * String to vector.
	 *
	 * @param vectorStr the vector str
	 *
	 * @return the vector3f
	 */
	private Vector3f stringToVector(String vectorStr) {
		vectorStr = vectorStr.substring(1,vectorStr.length()-1);
		StringTokenizer sT = new StringTokenizer(vectorStr,",");
		return new Vector3f(Float.parseFloat(sT.nextToken()),Float.parseFloat(sT.nextToken()),Float.parseFloat(sT.nextToken()));
	}
    /**
     * Building the mutationLibrary based on the data loaded on to mutationList field
     * mutation length is equal to the number of monomers that participate in the mutation
     */
    private void buildDictionaries() {
        mutationLibraries = new MutationLibrary[mutationList.size()+2];
        int currentDictionaryIndex = 2; // minimum mutation length is 2
        for (Vector<Mutation> vector : mutationList) {
            mutationLibraries[currentDictionaryIndex] = new MutationLibrary();
            for (Mutation mutation : vector) {
                mutation.setProbability(pm);
                addLibraryEntry(mutation, mutationLibraries[currentDictionaryIndex]);
            }
            currentDictionaryIndex++;
        }               
    }

    /**
     * Adds a mutation to a {@link MutationLibrary}.
     *  Six versions of  of each mutation are added to mutationLibrary entry. the method fill's for the given mutation all the possible vector in the given rotations
     * <p> 0 degrees on axis x
     * <p> 90 degrees on axis x
     * <p> -90 degrees on axis x
     * <p> 180 degrees on axis x
     * <p> 90 degrees on axis y
     * <p> -90 degrees on axis y
     * @param mutation the mutation
     * @param library the mutationLibrary
     */
    private void addLibraryEntry(Mutation mutation, MutationLibrary library)  {
        Vector3f positionVector = new Vector3f();
        double degree;
        char axis;
        MonomerDirection relative = MonomerDirection.FORWARD;
        MutationLibraryEntry newEntry;
        //TODO: check for duplicity in the Dictionary while putting mutation
        positionVector.sub(mutation.getLastMonomerVector(), mutation.getFirstMonomerVector());
//		put in library as it is
        newEntry = new MutationLibraryEntry(mutation,'x',0,relative, dimensions, matrixMan);
        library.put(positionVector, newEntry);

//		rotation of 90 deg around x axis
        degree = Math.PI /2;
        axis = 'x';
        if (dimensions == Dimensions.THREE) {
            relative = MonomerDirection.UP;
            newEntry = new MutationLibraryEntry(mutation,axis,degree,relative,dimensions, matrixMan);
            library.put(matrixMan.LorentzTransformation(positionVector, axis, degree), newEntry);
        }

//		rotation of -90 deg around x axis
        degree = -Math.PI /2;
        axis = 'x';
        if (dimensions == Dimensions.THREE) {
            relative = MonomerDirection.DOWN;
            newEntry =  new MutationLibraryEntry(mutation,axis,degree,relative,dimensions, matrixMan);
            library.put(matrixMan.LorentzTransformation(positionVector, axis, degree), newEntry);
        }


//		rotation of 180 deg around x axis
        degree = Math.PI ;
        axis = 'x';
        //TODO: check definition in here !!!
        relative = MonomerDirection.FORWARD;
        newEntry =  new MutationLibraryEntry(mutation,axis,degree,relative,dimensions, matrixMan);
        if ((dimensions == Dimensions.THREE) || (newEntry.getDirection().ordinal() <3))
            library.put(matrixMan.LorentzTransformation(positionVector,axis,degree), newEntry);

//		rotation of 90 deg around y axis
        degree = Math.PI / 2 ;
        axis = 'z';
        relative = MonomerDirection.LEFT;
        newEntry =   new MutationLibraryEntry(mutation,axis,degree,relative,dimensions, matrixMan);
        if ((dimensions == Dimensions.THREE) || (newEntry.getDirection().ordinal() <3))
            library.put(matrixMan.LorentzTransformation(positionVector,axis,degree), newEntry);

//		rotation of -90 deg around y axis
        degree = -Math.PI / 2 ;
        axis = 'z';
        relative = MonomerDirection.RIGHT;
        newEntry =  new MutationLibraryEntry(mutation,axis,degree,relative,dimensions, matrixMan);
        if ((dimensions == Dimensions.THREE) || (newEntry.getDirection().ordinal() <3))
            library.put(matrixMan.LorentzTransformation(positionVector,axis,degree), newEntry);
    }

     /**
     * mutate function is making a mutate according to lesh algorithm.
     * @param protein the protein to mutate.
     * @param out the protein that will be replaced.
     */
   public void  mutate(Protein protein, Protein out) {
        
    	boolean foundB = false;
    	boolean foundC = false;
		Grid grid = protein.getGrid();
		Conformation newConformation = new Conformation(protein.size());
		
		// Clone the conformation and set the conformation to the protein. It's done in order to set the cells in the grid.
		for (int monomerNumber = 0; monomerNumber < protein.conformation.size(); monomerNumber++)
	            newConformation.add(protein.conformation.get(monomerNumber));
		 
		protein.setConformation(newConformation);
		
		while (!foundB && !foundC){
			int randomI = random.nextInt(protein.size() - 1); // Get random monomer.
			Monomer monomerI = protein.get(randomI);
			Monomer monomerIplus1 = protein.get(randomI + 1);
			Monomer monomerIminus1 = randomI != 0 ? protein.get(randomI - 1) : null;
			int xi = monomerI.getX(); 
			int yi = monomerI.getY();
			int xiPlus1=monomerIplus1.getX();
			int yiPlus1=monomerIplus1.getY();
			
			Monomer monomerL=null;
			Monomer monomerC=null;
			
			// Now we are checking if we can activate one of lesh methods on the given monomers.
			
			if ((xi == xiPlus1 && yi == (yiPlus1 - 1)) || (xi == xiPlus1 && yi == (yiPlus1 + 1))) {  // option 1+2
				if (grid.isValidCell(xiPlus1 - 1,yiPlus1,0) && grid.isValidCell(xi-1, yi, 0)){
					monomerL = grid.getCell(xiPlus1 - 1, yiPlus1, 0);
					monomerC = grid.getCell(xi-1, yi, 0);
					if (monomerL == null){
						if (monomerC == monomerIminus1){ // B
							foundB = true;
							activateB(protein,out, randomI, xiPlus1 - 1,yiPlus1, monomerC);
							return;
						}
						else if (grid.getCell(xi-1, yi, 0) == null){ // C
							foundC = true;
							activateC(protein,out, randomI, xiPlus1 - 1,yiPlus1, xi-1, yi);
							return;
						} 
					}
				}
			} 
			if ((xi == (xiPlus1 - 1) && yi == yiPlus1) || (xi == (xiPlus1 + 1) && yi == yiPlus1)){ // option 3+4
				if (grid.isValidCell(xiPlus1, yiPlus1 + 1, 0) && grid.isValidCell(xi, yi+1, 0)){
					monomerL = grid.getCell(xiPlus1, yiPlus1 + 1, 0);
					monomerC = grid.getCell(xi, yi+1, 0);
					if (monomerL == null){ 
					   if (monomerC == monomerIminus1){
						   foundB = true;
						   activateB(protein, out, randomI, xiPlus1,yiPlus1 + 1, monomerC);
						   return;
					   }
					   else if (grid.getCell(xi, yi+1, 0) == null){
						   foundC= true;
						   activateC(protein, out, randomI, xiPlus1,yiPlus1 + 1, xi, yi+1);
						   return;
					   }
					}
				}
			}
			if ((xi == xiPlus1 && yi == (yiPlus1 - 1)) || (xi == xiPlus1 && yi == (yiPlus1 + 1))){ // option 5+6
				if (grid.isValidCell(xiPlus1+1, yiPlus1, 0) && grid.isValidCell(xi+1, yi, 0)){
					monomerL = grid.getCell(xiPlus1+1, yiPlus1, 0);
					monomerC = grid.getCell(xi+1, yi, 0);
					if (monomerL == null){
						if(monomerC == monomerIminus1){
							   foundB = true;
							   activateB(protein, out, randomI, xiPlus1+1,yiPlus1, monomerC);
							   return;
						}	 
						else if (grid.getCell(xi+1, yi, 0) == null){
						   foundC= true;
						   activateC(protein, out, randomI, xiPlus1+1,yiPlus1, xi+1, yi);
						   return;
					   }
					}
				}
			}
			if ((xi == (xiPlus1 - 1) && yi == yiPlus1) || (xi == (xiPlus1 + 1) && yi == yiPlus1)){ // option 7+8
				if (grid.isValidCell(xiPlus1, yiPlus1-1, 0) && grid.isValidCell(xi, yi-1, 0)){
					monomerL = grid.getCell(xiPlus1, yiPlus1-1, 0);
					monomerC = grid.getCell(xi, yi-1, 0);
					if ( monomerL == null ){
						if(monomerC == monomerIminus1){
							   foundB = true;
							   activateB(protein, out, randomI, xiPlus1,yiPlus1-1, monomerC);
							   return;
						   }
						else if (grid.getCell(xi, yi-1, 0) == null){  
						   foundC = true;
						   activateC(protein, out, randomI, xiPlus1,yiPlus1-1, xi, yi-1);
						   return;
						}
					}
				}
			}
		}
    }
   
  /**
   * This function activates case B from lesh article - In this case MonomerC is the monomer before 
   * monomerI and we need to change the place of monomerI to be in L. 
   * @param protein The protein to mutate.
   * @param out The proteing that should be replaced.
   * @param randomI The index of the selected monomer.
   * @param xL The x value of L.
   * @param yL The y value of L.
   * @param monomerC The monomer in C point.
   */
    private void activateB(Protein protein,Protein out, int randomI, int xL,int yL, Monomer monomerC){
    	Grid grid = protein.getGrid();
    	protein.cleanGrid();
    	Monomer monomerI = protein.get(randomI);
    	monomerI.setX(xL);
    	monomerI.setY(yL);
      	Conformation originalConformation = protein.conformation;
    	Conformation newConformation = new Conformation(protein.size());
    	
    	// Copy the conformation before the mutation.
        for (int monomerNumber = 0; monomerNumber <= randomI - 1 && monomerNumber < protein.size(); monomerNumber++)
            newConformation.add(originalConformation.get(monomerNumber));
        
        Monomer randomIminus2 = randomI > 1 ? protein.get(randomI -2): null;
        Monomer randomIminus1 = randomI > 0 ? protein.get(randomI -1): null;
        Monomer randomIplus1 = protein.get(randomI + 1);
        Monomer randomIplus2 = randomI < protein.size() - 2 ? protein.get(randomI + 2) : null;
        
        // Mutation
    	if (randomI >= 2 && randomI < protein.size()-2){
        	newConformation.add(getNewDirection(randomIminus2, randomIminus1, monomerI)); // Change randomI conformation
            newConformation.add(getNewDirection(randomIminus1, monomerI, randomIplus1));// Change randomI+1 conformation
            newConformation.add(getNewDirection(monomerI, randomIplus1, randomIplus2));// Change randomI+2 conformation
        }	else if (randomI==0 && protein.size() == 2){
        	newConformation.add(MonomerDirection.FIRST);
        	newConformation.add(MonomerDirection.FORWARD);
        }	else if (randomI==0){
        	newConformation.add(MonomerDirection.FIRST);
        	newConformation.add(MonomerDirection.FORWARD);
        	newConformation.add(getNewDirection(monomerI, randomIplus1, randomIplus2));// Change randomI+2 conformation
        }	else if (randomI==1 && protein.size() == 3){
        	newConformation.add(MonomerDirection.FORWARD);
            newConformation.add(getNewDirection(randomIminus1, monomerI, randomIplus1));// Change randomI+1 conformation
        }  else if (randomI==1){
        	newConformation.add(MonomerDirection.FORWARD);
            newConformation.add(getNewDirection(randomIminus1, monomerI, randomIplus1));// Change randomI+1 conformation
            newConformation.add(getNewDirection(monomerI, randomIplus1, randomIplus2));// Change randomI+2 conformation
        }  else if (randomI==protein.size()-2){
        	newConformation.add(getNewDirection(randomIminus2, randomIminus1, monomerI)); // Change randomI conformation
            newConformation.add(getNewDirection(randomIminus1, monomerI, randomIplus1));// Change randomI+1 conformation
        }  
       
      
        // Copy the conformation after the mutation.
        for (int monomerNumber = randomI + 3; monomerNumber < protein.size(); monomerNumber++)
            newConformation.add(originalConformation.get(monomerNumber));
        
        // Set the new conformation of out.
        out.setConformation(newConformation);        
    	grid.reset(out);
    }
    
    /**
     * This function activates case C from lesh article - In this case we need to replace the place of 
     * monomerI to be in L, and to change the chain before monomer I until we get a completet state. 
     * @param protein The protein to mutate.
     * @param out The proteing that should be replaced.
     * @param randomI The index of the selected monomer.
     * @param xL The x value of L.
     * @param yL The y value of L.
     * @param monomerC The monomer in C point.
     */
    private void activateC(Protein protein,Protein out, int randomI, int xL,int yL, int xC, int yC){
    	
    	int minus2OldX,minus2OldY,minus1OldX,minus1OldY;
    	Monomer monomerI = protein.get(randomI);
    	Monomer monomerIminus1= protein.get(randomI-1);
    	double distance = 0;
    	Grid grid = protein.getGrid();
    	protein.cleanGrid();
    	int xI = monomerI.getX();
    	int yI = monomerI.getY();
        	
    	// Saving the original location of I. We need to save the coordinates of last two 
    	// monomers before the monomer we've just changed its place. In the beggining, we are saving the 
    	// place of monomerI.
    	minus2OldX = xI; minus2OldY = yI;
    	
    	// Saving original location of i-1
    	minus1OldX = monomerIminus1.getX();
    	minus1OldY = monomerIminus1.getY();
    	
    	// Monomer i is moving to L.
    	monomerI.setX(xL);
    	monomerI.setY(yL);
    	// Monomer i-1 is moving to C.
    	monomerIminus1.setX(xC);
    	monomerIminus1.setY(yC);
    	
    	// lastChangesMonomer = The last monomer who changed its place.
    	int lastChangedMonomerNumber = randomI - 1;
    	Monomer lastChangedMonomer = monomerIminus1;
    		
    	while (!lastChangedMonomer.getRelativeDirection().equals(MonomerDirection.FIRST)){
    		
    		// PrevMonomer = The monomer before the last monomer that has been changed.
    		Monomer prevMonomer = protein.get(lastChangedMonomerNumber - 1);
    		
    		// Calculate the distance between the last monomer that changed its place and the monomer before it.
        	// If the distance equals to 1, or we reached the first monomer,
        	// then the move is complete, otherwise, continue.
    		distance = calculateDistance(lastChangedMonomer, prevMonomer);
        	if (distance == 1){ // If distance = 1, we finish.
        		break;
        	}
        	
        	// Vertex prevMonomer is moved to the position previously held by vertex lastChangesMonomer-1.
        	// For example - vertex i-2 moves to where i has been. vertex i-3 moves to where i-1 has been.
        	int prevMonomerX = prevMonomer.getX();
        	int prevMonomerY = prevMonomer.getY();
        	prevMonomer.setX(minus2OldX);
        	prevMonomer.setY(minus2OldY);
        	// Save original monomers locations
        	minus2OldX = minus1OldX;
        	minus2OldY = minus1OldY;
        	minus1OldX = prevMonomerX;
        	minus1OldY = prevMonomerY;
        	
        	// Change the currentMonomer to prevMonomer
        	lastChangedMonomer = prevMonomer;
        	lastChangedMonomerNumber = lastChangedMonomerNumber - 1;
       	}
        	
      	Conformation newConformation = createNewConformation(protein, randomI,lastChangedMonomerNumber, protein.conformation);
        out.setConformation(newConformation); // Set the new conformation.        
    	grid.reset(out);
    }

    /**
     * Create new Conformation for activateC moves.
     * @param protein the protein we calculate the conformation on it.
     * @param randomI the random I number.
     * @param lastChangedMonomerNumber the last monomer that changed its place.
     * @param originalConformation the original conformation.
     * @return the new conformation.
     */
	private Conformation createNewConformation(Protein protein, int randomI,int lastChangedMonomerNumber, Conformation originalConformation) {
		Conformation newConformation = new Conformation(protein.size());
    	// conformation before mutation.
        for (int monomerNumber = 0; monomerNumber <= lastChangedMonomerNumber - 1 && monomerNumber < protein.size(); monomerNumber++)
            newConformation.add(originalConformation.get(monomerNumber));
    	// Mutation
          Monomer currentMonomer = protein.get(lastChangedMonomerNumber);

     	  Monomer currentMonomerMinus1 = (lastChangedMonomerNumber > 0 ) ? protein.get(lastChangedMonomerNumber - 1) : null;
	 	  Monomer currentMonomerMinus2 = (lastChangedMonomerNumber > 1 ) ?protein.get(lastChangedMonomerNumber - 2) : null;
	 	  for (int monomerNumber = lastChangedMonomerNumber; monomerNumber <= randomI + 2 && monomerNumber < protein.size(); monomerNumber++){
	    	    newConformation.add(getNewDirection(currentMonomerMinus2, currentMonomerMinus1, currentMonomer)); // Change monomerNumber conformation
	    	    currentMonomerMinus2 = currentMonomerMinus1;
	    	    currentMonomerMinus1 = currentMonomer;
	    	    currentMonomer = monomerNumber < protein.size() - 1 ? protein.get(monomerNumber + 1) : null;
	      }
	    // Conformation after mutation
        for (int monomerNumber = randomI + 3; monomerNumber < protein.size(); monomerNumber++)
            newConformation.add(originalConformation.get(monomerNumber));
        
		return newConformation;
	}

    
    /**
     * Return the distance between the two monomers
     * @param monomer1 
     * @param monomer2
     * @return the distnace between the monomers.
     */
	private double calculateDistance(Monomer monomer1,Monomer monomer2) {
		return Math.sqrt(Math.pow((monomer1.getX()-monomer2.getX()), 2) +
				  Math.pow((monomer1.getY() - monomer2.getY()), 2));
	}
    
    /**
     * Returns the direction of p3 according to p1 and p2 direction
     * @param p1 The monomer before p2
     * @param p2 The monomer before p3
     * @param p3 The monomer we want to get its direction
     * @return the direction of p3.
     */
    private MonomerDirection getNewDirection(Monomer p1, Monomer p2, Monomer p3){
    	
    	if (p2 == null) { // p3 is the first monomer
    		return MonomerDirection.FIRST;
    	}
    	
    	if (p1 == null){ // p3 is the second monomer
    		return MonomerDirection.FORWARD; //TODO: Check what should be here
    	}
    		
    	 int diff_1_2_X = p1.getX() - p2.getX();
    	 int diff_1_2_Y = p1.getY() - p2.getY();
    	 int diff_2_3_X = p2.getX() - p3.getX();
    	 int diff_2_3_Y = p2.getY() - p3.getY();
    	 
    	 if ( diff_1_2_X == -1 && diff_1_2_Y == 0 ){ //1
		 	if (diff_2_3_X == 0 && diff_2_3_Y == -1){
    			return MonomerDirection.LEFT;
    		} else if(diff_2_3_X == -1 && diff_2_3_Y == 0){
    			return MonomerDirection.FORWARD;
    		} else if(diff_2_3_X == 0 && diff_2_3_Y == 1){
    			return MonomerDirection.RIGHT;
    		}
		 	
    	 } else if ( diff_1_2_X == 0 && diff_1_2_Y == -1 ){ //2
    		if (diff_2_3_X == 1 && diff_2_3_Y == 0){
     			return MonomerDirection.LEFT;
     		} else if(diff_2_3_X == 0 && diff_2_3_Y == -1){
     			return MonomerDirection.FORWARD;
     		} else if(diff_2_3_X == -1 && diff_2_3_Y == 0){
     			return MonomerDirection.RIGHT;
     		}
    		 
    	 } else if ( diff_1_2_X == 1 && diff_1_2_Y == 0 ){ //3
    		 if (diff_2_3_X == 0 && diff_2_3_Y == 1){
      			return MonomerDirection.LEFT;
      		} else if(diff_2_3_X == 1 && diff_2_3_Y == 0){
      			return MonomerDirection.FORWARD;
      		} else if(diff_2_3_X == 0 && diff_2_3_Y == -1){
      			return MonomerDirection.RIGHT;
      		}
    		 
    	 } else if ( diff_1_2_X == 0 && diff_1_2_Y == 1 ){ //4
    		 if (diff_2_3_X == -1 && diff_2_3_Y == 0){
       			return MonomerDirection.LEFT;
       		} else if(diff_2_3_X == 0 && diff_2_3_Y == 1){
       			return MonomerDirection.FORWARD;
       		} else if(diff_2_3_X == 1 && diff_2_3_Y == 0){
       			return MonomerDirection.RIGHT;
       		}
    	 }
    	     	 
    	 return null;
    }
    
}

